﻿using Microsoft.Win32;
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Text.RegularExpressions;

namespace ResumeVideo
{
    public enum PlayStatus
    {
        Stopped,
        Playing,
        Paused
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool state;
        private bool isDragging;
        private DispatcherTimer timer;
        private DispatcherTimer mouseTimer;
        private MovieList movieList;
        private const string ProgramTitle = "Resume Video Player";
        private const string AcceptedMovieTypes = "Movie Files (*.mov;*.avi;*.vmw;*.m4v)|*.mov;*.avi;*.vmw;*.m4v|All files (*.*)|*.*";
        private double horizontalBorderHeight = SystemParameters.ResizeFrameHorizontalBorderHeight;
        private double verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;
        private double captionHeight = SystemParameters.CaptionHeight;

        public string StartupMovie { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            state = false;
            mediaElement1.LoadedBehavior = MediaState.Manual;
            mediaElement1.MediaOpened += new RoutedEventHandler(mediaElement1_MediaOpened);

            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(2);
            timer.Tick += new EventHandler(timer_Tick);

            mouseTimer = new DispatcherTimer();
            mouseTimer.Interval = TimeSpan.FromSeconds(3);
            mouseTimer.Tick += new EventHandler(mouseTimer_Tick);
            VolumeSlider.Value = Properties.Settings.Default.Volume;

            movieList = new MovieList();
            if (Properties.Settings.Default.ResumeFile == string.Empty)
                OpenResumeFile();

            LoadResumeFile();
            BindDropDownList();
        }

        #region Events
        private void mediaElement1_MediaOpened(object sender, RoutedEventArgs e)
        {
            if (mediaElement1.NaturalDuration.HasTimeSpan)
            {
                TimeSpan ts = mediaElement1.NaturalDuration.TimeSpan;
                seekBar.Maximum = ts.TotalSeconds;
                seekBar.SmallChange = 1;
                seekBar.LargeChange = Math.Min(12, ts.Seconds / 10);
            }
            timer.Start();

            ResizeWindow(1);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            SaveMediaPosition();
            Properties.Settings.Default.Volume = VolumeSlider.Value;
            Properties.Settings.Default.Save();
        }

        private void mediaElement1_MediaEnded(object sender, RoutedEventArgs e)
        {
            movieList.Movies.RemoveAll(m => m.Path == mediaElement1.Source.LocalPath);
            SaveResumeFile();

            mediaElement1.Source = null;
            this.Title = ProgramTitle;

            SetButtonState();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ControlGrid.Opacity = 0;
            if (string.IsNullOrEmpty(StartupMovie))
                CheckResume();
            else
                OpenMovie(new FileInfo(StartupMovie));
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (!isDragging)
            {
                seekBar.Value = mediaElement1.Position.TotalSeconds;

                string formatted = (DateTime.Today + mediaElement1.Position).ToString("HH:mm:ss");

                txtPosition.Content = formatted;
            }
        }

        private void mouseTimer_Tick(object sender, EventArgs e)
        {
            if (WindowState == WindowState.Maximized)
            {
                mouseTimer.Stop();
                Cursor = Cursors.None;
            }
        }

        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            if (e != null)
            {
                Button o = (Button)e.Source;
                if (o != null && o.CommandParameter != null)
                {
                    var movie = from m in movieList.Movies
                                where m.MovieId == (Guid)o.CommandParameter
                                select m;
                    if (movie != null && movie.Count() > 0)
                    {
                        movieList.Movies.Remove(movie.First());
                    }
                    BindDropDownList();
                }
            }
        }

        private void Window_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (files.Count() == 1)
                {
                    FileInfo file = new FileInfo(files[0]);
                    if (file.Extension == "avi" ||
                        file.Extension == "vmw" ||
                        file.Extension == "mov")
                    {
                        e.Effects = DragDropEffects.All;
                    }
                }
                else
                {
                    e.Effects = DragDropEffects.None;
                }
            }
        }

        private void Window_Drop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
            if (files.Count() == 1)
            {
                FileInfo file = new FileInfo(files[0]);
                OpenMovie(file);
            }
        }
        #endregion

        #region Mouse and Keyboard events
        private void seekBar_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            isDragging = true;
        }

        private void seekBar_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            mediaElement1.Position = TimeSpan.FromSeconds(seekBar.Value);
            isDragging = false;
        }

        private void seekBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            mediaElement1.Position = TimeSpan.FromSeconds(seekBar.Value);
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Escape:
                    ToggleFullScreen();
                    break;
                case Key.MediaStop:
                    Stop();
                    break;
                case Key.Left:
                    mediaElement1.Position += TimeSpan.FromSeconds(-15);
                    break;
                case Key.Right:
                    mediaElement1.Position += TimeSpan.FromSeconds(15);
                    break;
                //case Key.VolumeDown:
                //    break;

                //case Key.VolumeUp:
                //    break;
                case Key.Space:
                case Key.Enter:
                case Key.MediaPlayPause:
                    StartPause();
                    break;
                case Key.D1:
                    ResizeWindow(1);
                    break;
                case Key.D2:
                    ResizeWindow(2);
                    break;
                case Key.D3:
                    ResizeWindow(3);
                    break;
                case Key.D4:
                    ResizeWindow(4);
                    break;
            }
        }

        private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            VolumeSlider.Value = VolumeSlider.Value + ((e.Delta / 120) * 0.05);
        }

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            StartPause();
        }

        private void cmbPreviousMovies_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (cmbPreviousMovies.SelectedItem != null)
            {
                SaveMediaPosition();
                Movie selectedMovie = (Movie)cmbPreviousMovies.SelectedItem;
                BindDropDownList();
                PlayMovie(selectedMovie);
            }
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            StartPause();
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            Stop();
            SetButtonState();
        }

        private void btnOpen_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog file = new OpenFileDialog();
            file.Filter = AcceptedMovieTypes;
            if (file.ShowDialog().Value)
            {
                FileInfo openFile = new FileInfo(file.FileName);
                OpenMovie(openFile);
            }
        }

        private void btnOpen_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            OpenResumeFile();
        }

        private void btnFullScreen_Click(object sender, RoutedEventArgs e)
        {
            ToggleFullScreen();
        }

        private void Grid_MouseEnter(object sender, MouseEventArgs e)
        {
            ControlGrid.Opacity = 1;
        }

        private void ControGrid_MouseLeave(object sender, MouseEventArgs e)
        {
            if (state == false)
            {
                //DoubleAnimation da = new DoubleAnimation(1, 0, new Duration(TimeSpan.FromSeconds(1.5)));
                //ControlGrid.BeginAnimation(Grid.OpacityProperty, da);

                ControlGrid.Opacity = 0;
            }
        }

        private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ToggleFullScreen();
        }

        private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            switch (this.WindowState)
            {
                case WindowState.Maximized:
                    Cursor = Cursors.Hand;
                    mouseTimer.Interval = TimeSpan.FromSeconds(4);
                    mouseTimer.Start();
                    break;
                case WindowState.Minimized:
                    break;
                case WindowState.Normal:
                    break;
                default:
                    break;
            }
        }
        #endregion

        #region Methods
        private void OpenResumeFile()
        {
            SaveFileDialog resumeFile = new SaveFileDialog();
            resumeFile.CreatePrompt = true;
            resumeFile.RestoreDirectory = true;
            resumeFile.AddExtension = true;
            resumeFile.FileName = "ResumePlay.xml";
            resumeFile.Title = "Select location of resume file";
            resumeFile.DefaultExt = "xml";
            if (resumeFile.ShowDialog().Value)
            {
                if (resumeFile.FileName != string.Empty)
                {
                    Properties.Settings.Default.ResumeFile = resumeFile.FileName;
                    Properties.Settings.Default.Save();
                    LoadResumeFile();
                }
            }
        }

        private void SaveResumeFile()
        {
            if (Properties.Settings.Default.ResumeFile != string.Empty && File.Exists(Properties.Settings.Default.ResumeFile))
                movieList.Save(Properties.Settings.Default.ResumeFile);
        }

        private void LoadResumeFile()
        {
            if (Properties.Settings.Default.ResumeFile != string.Empty && File.Exists(Properties.Settings.Default.ResumeFile))
                movieList.Load(Properties.Settings.Default.ResumeFile);
        }

        private void ToggleFullScreen()
        {
            switch (WindowState)
            {
                case WindowState.Maximized:
                    WindowStyle = WindowStyle.ThreeDBorderWindow;
                    WindowState = WindowState.Normal;
                    Cursor = Cursors.Hand;
                    mouseTimer.Stop();
                    break;
                case WindowState.Minimized:
                    mouseTimer.Stop();
                    break;
                case WindowState.Normal:
                    WindowStyle = WindowStyle.None;
                    WindowState = WindowState.Maximized;
                    //Cursor = Cursors.None;
                    mouseTimer.Start();
                    break;
                default:
                    mouseTimer.Stop();
                    break;
            }
        }

        private void StartPause()
        {
            switch (state)
            {
                case false:
                    btnStartImage.Source = CreateImageSource(Properties.Resources.Play);
                    Pause();
                    break;
                case true:
                    btnStartImage.Source = CreateImageSource(Properties.Resources.Pause);
                    Play();
                    break;
            }

            SetButtonState();

            state = !state;
        }

        private void SetButtonState()
        {
            if (state == false)
                btnStartImage.Source = CreateImageSource(Properties.Resources.Pause);
            else
            {
                btnStartImage.Source = CreateImageSource(Properties.Resources.Play);
            }

            ControlGrid.Opacity = state ? 0 : 1;
        }

        private void SaveMediaPosition()
        {
            Pause();
            if (mediaElement1.Source != null)
                movieList.SetLastPosition(new Movie { Path = mediaElement1.Source.LocalPath, LastComputer = Environment.MachineName, LastPosition = mediaElement1.Position.TotalSeconds });

            SaveResumeFile();
            BindDropDownList();
        }

        private void PlayMovie(Movie movie)
        {
            PlayMovie(movie.Path, movie.LastPosition);
        }

        #region PlayMovie
        private void PlayMovie(string path, double position)
        {
            mediaElement1.Source = new Uri(path);
            Play();
            mediaElement1.Position = TimeSpan.FromSeconds(position);
            SetButtonState();

            FileInfo fi = null;
            if (!string.IsNullOrEmpty(path))
                fi = new FileInfo(path);

            this.Title = "Resume Video Player - " + fi.Name;
        }
        #endregion

        private void OpenMovie(FileInfo file)
        {
            Movie openedMovie = new Movie
            {
                Path = file.FullName,
                LastComputer = Environment.MachineName,
                LastPosition = 0,
                MovieId = Guid.NewGuid()
            };

            movieList.Movies.Add(openedMovie);
            BindDropDownList();
            cmbPreviousMovies.SelectedItem = openedMovie;
            PlayMovie(openedMovie);
        }

        private void Pause()
        {
            mediaElement1.Pause();
            SetButtonState();
        }

        private void Play()
        {
            mediaElement1.Play();
            SetButtonState();
        }

        private void Stop()
        {
            mediaElement1.Stop();
            SetButtonState();
            this.Title = ProgramTitle;
        }

        private ImageSource CreateImageSource(Icon icon)
        {
            Bitmap bitmap = icon.ToBitmap();
            IntPtr hBitmap = bitmap.GetHbitmap();

            ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap(
                      hBitmap, IntPtr.Zero, Int32Rect.Empty,
                      BitmapSizeOptions.FromEmptyOptions());

            return wpfBitmap;
        }

        private void CheckResume()
        {
            if (movieList.Movies.Count == 1)
            {
                if (MessageBox.Show(string.Format("Do you want to resume the previous movie\n{0} from {1}", movieList.Movies.First().Path, movieList.Movies.First().LastPositionTime), "Resume movie", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes) == MessageBoxResult.Yes)
                {
                    Movie movie = movieList.Movies.First();

                    PlayMovie(movie);
                }
            }
        }

        private void ResizeWindow(int factor)
        {
            if (mediaElement1.NaturalVideoWidth > 0)
            {
                this.Width = (mediaElement1.NaturalVideoWidth * factor) + 2 * verticalBorderWidth;
                this.Height = (mediaElement1.NaturalVideoHeight * factor) + captionHeight + 2 * horizontalBorderHeight;
                this.Left = (SystemParameters.PrimaryScreenWidth / 2) - (this.Width / 2);
                this.Top = (SystemParameters.PrimaryScreenHeight / 2) - (this.Height / 2);
            }
        }

        private void BindDropDownList()
        {
            cmbPreviousMovies.ItemsSource = movieList.Movies;

            //JumpList jumpList = new JumpList();

            //foreach (var movie in movieList.Movies)
            //{
            //    JumpTask task = new JumpTask
            //    {
            //        Title = movie.Name,
            //        Arguments = movie.MovieId.ToString(),
            //        Description = "Play this movie",
            //        CustomCategory = "Actions",
            //        IconResourcePath = Assembly.GetEntryAssembly().CodeBase,
            //        ApplicationPath = Assembly.GetEntryAssembly().CodeBase
            //    };
            //    jumpList.JumpItems.Add(task);
            //}

            //jumpList.ShowFrequentCategory = false;
            //jumpList.ShowRecentCategory = false;

            //JumpList.SetJumpList(Application.Current, jumpList);
        }

        #endregion
    }
}
